use async_trait::async_trait;
use clap::Parser;
use sha2::{Digest, Sha224, Sha256, Sha384, Sha512, Sha512_224, Sha512_256};

use crate::commands::commands::Command;
use crate::models::models;
use crate::models::models::command::CommandState;
use crate::utils::command;

#[derive(Debug, Default, Clone, Parser)]
#[clap(disable_help_flag = true)]
struct Args {
    // sha256-224
    #[arg(long = "256-224", default_value_t = false)]
    s_256_224: bool,
    // sha512-224
    #[arg(long = "512-224", default_value_t = false)]
    s_512_224: bool,
    // sha512-256
    #[arg(long = "512-256", default_value_t = false)]
    s_512_256: bool,
    // sha512
    #[arg(long = "512", default_value_t = false)]
    s_512: bool,
    // sha512-384
    #[arg(long = "512-384", default_value_t = false)]
    s_512_384: bool,
    // 是否转为大写
    #[arg(short = 'u', long = "upper", default_value_t = false)]
    upper: bool,
    // 字符串
    value: String,
}

#[derive(Debug, Default, Clone)]
pub(crate) struct ShaCommand {}

#[async_trait]
impl Command for ShaCommand {
    async fn execute(&self, command: models::command::Command) -> models::command::Command {
        let args = command::parse_command_args::<Args>(command.args.as_str());
        if args.is_err() {
            return self.save_command_output(command, CommandState::Success, args.unwrap_err().to_string());
        }

        let args = args.unwrap();

        if args.s_256_224 {
            let mut hasher = Sha224::new();
            hasher.update(args.value.as_bytes());

            let mut result = format!("{:x}", hasher.finalize());
            if args.upper {
                result = result.to_uppercase();
            }

            return self.save_command_output(command, CommandState::Success, result);
        }

        if args.s_512_224 {
            let mut hasher = Sha512_224::new();
            hasher.update(args.value.as_bytes());

            let mut result = format!("{:x}", hasher.finalize());
            if args.upper {
                result = result.to_uppercase();
            }

            return self.save_command_output(command, CommandState::Success, result);
        }

        if args.s_512_256 {
            let mut hasher = Sha512_256::new();
            hasher.update(args.value.as_bytes());

            let mut result = format!("{:x}", hasher.finalize());
            if args.upper {
                result = result.to_uppercase();
            }

            return self.save_command_output(command, CommandState::Success, result);
        }

        if args.s_512 {
            let mut hasher = Sha512::new();
            hasher.update(args.value.as_bytes());

            let mut result = format!("{:x}", hasher.finalize());
            if args.upper {
                result = result.to_uppercase();
            }

            return self.save_command_output(command, CommandState::Success, result);
        }

        if args.s_512_384 {
            let mut hasher = Sha384::new();
            hasher.update(args.value.as_bytes());

            let mut result = format!("{:x}", hasher.finalize());
            if args.upper {
                result = result.to_uppercase();
            }

            return self.save_command_output(command, CommandState::Success, result);
        }

        let mut hasher = Sha256::new();
        hasher.update(args.value.as_bytes());

        let mut result = format!("{:x}", hasher.finalize());
        if args.upper {
            result = result.to_uppercase();
        }

        self.save_command_output(command, CommandState::Success, result)
    }
}